package com.ds.springboot.service;

import com.ds.springboot.mapper.EmpMapper;
import com.ds.springboot.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @program: springboot-1-cache
 * @description:
 * @author: Dawson.Zhang
 * @create: 2020-05-17
 **/

/**
 * @CacheConfig公共缓存，公共的属性
 */
@CacheConfig(cacheNames = "emp")
@Service
public class EmpServiceImpl implements EmpService {
    @Resource
    EmpMapper mapper;

    /**
     * 将方法的运行结果进行缓存，以后再要相同的数据，直接从缓存中获取，不用调用方法
     *
     * cacheManager管理多个Cache组件的，对缓存的真正CRUD操作在Cache组件中，每一个缓存组件有自己唯一的名字。
     * 几个属性：
     *      cacheNames/value：指定缓存组件的名字
     *      key：缓存数据使用的key；可以用它来制定，默认使用方法参数的值，
     *          编写SpEL； #id；参数id的值   也可以用 #a0/#p0/#root.args[0]来获取参数id的值
     *
     *      keyGenerator：key的生辰器，可以指定key的生成器的组件id，
     *      key/keyGenerator只能选择一个使用
     *
     *      cacheManager：指定缓存管理器；或者cacheResolver指定获取解析器
     *
     *      condition：指定符合条件的情况下才缓存数据
     *
     *      unless：否定缓存，当unless指定的条件为true，方法的返回值就不会被缓存，可以获取到结果在进行判断
     *
     * @param id
     * @return
     */
    @Override
    @Cacheable(/*cacheNames = "emp"*//*, key = "#a0", condition = "#id>1", unless = "#id==2"*/)
    public Employee getById(Integer id) {
        return mapper.getById(id);
    }

    /**
     * @CachePut测试步骤,被标注的方法一定会执行
     *  1：查询id编号为1的员工，查询的结果会放在缓存里面。在没有更新缓存的情况下，以后查询编号为1的这个员工，数据还是缓存之前的数据。
     *
     *  2：修改编号为1的员工，注意，@Cacheput的key值要和Cacheable的key值要保持一致。
     *      因为在Cacheput在方法运行完之后，会在cacheNames中根据key的值去缓存中查找和这个key一样的数据，然后修改缓存中数据。
     *
     *
     * @param employee
     * @return
     */
    @Override
    @CachePut(/*cacheNames = "emp",*/key = "#employee.id")
    public Employee updateEmp(Employee employee) {
        int i = mapper.updateEmp(employee);
        return employee;
    }

    /**
     * @CacheEvict 方法运行完的时候，会在CacheNames中寻找对应的key值，然后清除对应缓存的数据
     *              allEntries清除缓存中所有的数据
     *              beforeInvocation=true，在方法运行之前清除缓存。主要是存在：如果方法出现了异常，那么
     *                                     就不会清除缓存，如果是在方法之前清除，那么不管方法有无异常，
     *                                     都会清除缓存
     *
     * @param id
     * @return
     */
    @Override
    @CacheEvict(/*cacheNames = "emp",*/key = "#id"/*,allEntries = true*/ )
    public int delEmp(Integer id) {
        return mapper.delEmp(id);
    }

    @Override
    public Employee addMap(Employee employee) {
        mapper.addEmp(employee);
        return employee;
    }

    @Override
    /**
     *Caching注解：
     *      适用于复杂的缓存情况，
     *          我们会发现使用lastName执行查询之后，后续的查询还是会访问数据库
     *          因为被@Cacheput标注之后，改方法一定会被执行
     *      为什么用id查询的话就没用经过数据库呢，因为上面的getByID()方法没有被@Cacheput标注
     */
    @Caching(
        cacheable = {
            @Cacheable(/*cacheNames = "emp",*/key = "#lastName")
        },
        put = {
            @CachePut(
               /* cacheNames = "emp",*/key = "#result.email"
            ),
            @CachePut(
               /* cacheNames = "emp",*/key = "#result.id"
            )
        }
    )
    public Employee getByLastName(String lastName) {
        return mapper.getByLastName(lastName);
    }
}
